﻿#ifndef ___PCLIB_S_SYSTUTIL___
#define ___PCLIB_S_SYSTUTIL___


#include "../m_core/m_core.hpp"

//X11/Xlib.h定义在这里的原因是它和rapidjson冲突；
//必须先include rapidjson的头文件，再include xlib.h才能编译通过
//QT在Linux下和X11冲突，如果使用Qt，则不使用X11
#if defined(PCOS_LINUX) && !defined(PCOS_ANDROID) && !defined(QT_VERSION)
    #include <X11/Xlib.h>
#endif


/**
*@brief        屏幕信息
*/
typedef struct _PCSCREENINFO
{
    bool main;              //是否为主屏
    char name[MAX_PATH];    //显示器在操作系统里面的枚举名称，如 \\.\DISPLAY1
    char model[MAX_PATH];   //显示器显示驱动型号名称，如 NVIDIA GeForce GT 630
    int  id;                //显示器在操作系统中的id号

    long left;              //显示器左坐标
    long top;               //显示器上坐标
    unsigned long width;    //显示器宽度
    unsigned long height;   //显示器高度

}PCSCREENINFO;

/**
*@brief        进程信息
*/
typedef struct _PCPROCESSINFO
{
    std::string  name;          //进程名
    std::string  cmdline;       //进程启动的命令行参数
    std::string  extinfo;       //扩展信息
    int        pid;             //进程id    
    int        ppid;            //父进程id
    int        priclassbase;    //优先权
    unsigned int threads;       //线程数
    bool       is64bit;         //是否位64位进程

    uint64_t mem_pagefile;      //内存：任务管理器(提交大小)
    uint64_t mem_workingset;    //内存：任务管理器(工作集(内存))resident

    uint64_t cpu_user;          //cpu:从进程启动到现在，本进程CPU处于用户态的运行时间。
    uint64_t cpu_sys;           //cpu:从进程启动到现在，本进程CPU处于内核态的运行时间
    uint64_t cpu_total;         //cpu:从进程启动到现在，本进程CPU的用户态和内核态的总运行时间
    int      cpu_usage;         //预留：cpu占用率，范围[0,10000]，cpu占用率需要你自己统计，这里仅加入这个字段方便使用
}PCPROCESSINFO;

/**
*@brief        cpu信息
*/
typedef struct _PCCPUINFO{
    uint64_t user;          //从系统启动到现在，CPU处于用户态的运行时间。
    uint64_t sys;           //从系统启动到现在，CPU处于内核态的运行时间。注意，不包括系统空闲进程
    uint64_t idle;          //从系统启动到现在，CPU处于空闲的时间。
    uint64_t total;         //从系统启动到现在，CPU总运行时间。
    int      usage;         //预留：cpu占用率，范围[0,10000]，cpu占用率需要你自己统计，这里仅加入这个字段方便使用

    std::string vendor;     //cpu提供商
    std::string name;       //cpu名称
    int         mhz;        //cpu频率
} PCCPUINFO;

/**
*@brief        内存信息
*/
typedef struct _PCMEMINFO{
    uint64_t total;         //总内存字节数
    uint64_t free;          //空闲内存字节数
    uint64_t used;          //已使用内存字节数

    uint64_t swaptotal;     //swap:总内存字节数
    uint64_t swapfree;      //swap:空闲内存字节数
    uint64_t swapused;      //swap:已使用内存字节数
} PCMEMINFO;

/**
*@brief        系统信息
*/
typedef struct _PCPCSYSTEMINFO
{
    int os_version_major;   //操作系统主版本号
    int os_version_minor;   //操作系统次版本号
    std::string os_name;    //操作系统版本号名称
    std::string arch_name;  //处理器架构
    unsigned int pagesize;  //页大小    
    bool        is64bit;    //是否为64位操作系统
}PCSYSTEMINFO;

/**
*@brief        单个文件分区信息
*/
typedef struct _PCFSPARTINFO{
    std::string name;       //名称，c: d:
    std::string dev_type;   //设备类型 fixed cdrom
    std::string fs_type;    //文件系统类型 ntfs ext3

    uint64_t total;         //总空间字节数
    uint64_t free;          //空闲空间字节数
    uint64_t used;          //已使用空间字节数
} PCFSINFO;


/**
*@brief      系统操作工具类
*/
class CPCSysUtil : CPCNoCopyable
{
public:
    /**
    *@brief     获取cpu信息
    *@param     vecInfo    [out]    取到的cpu信息。
    *@return    是否成功
    */
    static CPCResult<> GetCpuInfo(std::vector<PCCPUINFO>& vecCpuInfo)
    {
        CPCResult<> result;
        vecCpuInfo.clear();
#if defined(PCOS_WIN) 
        DWORD retval = 0;
        SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION info[MAX_PATH];
        PCWIN_USE_API(NTDLL,NtQuerySystemInformation);
        PC_NtQuerySystemInformation(SystemProcessorPerformanceInformation, &info, sizeof(info), &retval);
        if (!PC_NtQuerySystemInformation || !retval)
        {
            return result.SetSystemFail();
        }

        int num = retval / sizeof(info[0]);
        for (int i = 0; i< num; i++)
        {
            PCCPUINFO tmp;
            tmp.usage = 0;
            tmp.idle = info[i].IdleTime.QuadPart / 10000;
            tmp.user = info[i].UserTime.QuadPart / 10000;
            tmp.sys = (info[i].KernelTime.QuadPart - info[i].IdleTime.QuadPart) / 10000;
            tmp.total = tmp.idle + tmp.user + tmp.sys;
            if (tmp.total == 0) tmp.total = 1;

            char szPath[MAX_PATH];
            snprintf(szPath, sizeof(szPath), "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\%d", i);
            CPCRegistry reg;
            auto result2 = reg.ReadReg(HKEY_LOCAL_MACHINE, szPath, "VendorIdentifier");
            if (result2)
            {
                tmp.vendor = result2.Get().second;
            }
            result2 = reg.ReadReg(HKEY_LOCAL_MACHINE, szPath, "ProcessorNameString");
            if (result2)
            {
                tmp.name = result2.Get().second;
            }
            auto result3 = reg.ReadRegDWORD(HKEY_LOCAL_MACHINE, szPath, "~MHz");
            if (result3)
            {
                tmp.mhz = result3.Get();
            }
            else
            {
                tmp.mhz = -1;
            }
            vecCpuInfo.push_back(tmp);
        }
#else
        int cpucount = (int)sysconf(_SC_NPROCESSORS_CONF);
        std::vector<std::string> ret = CPCFileUtil::PCReadFileLines("/proc/stat");
        if (ret.size() < (cpucount + 1))
        {
            return result.SetSystemFail();
        }

        //获取cpu时间信息
        for (size_t i = 0; i < cpucount; i++)
        {
            PCCPUINFO tmp;
            tmp.usage = 0;
            tmp.mhz = -1;

            char* line = (char*)ret[i + 1].c_str();
            if (!line || strstr(line, "cpu") == NULL)
                break;
            char* ptr = CPCStrUtil::StrSkipToken(line);

            uint64_t user = 0, nice = 0, sys = 0, idle = 0, wait = 0, irq = 0, soft_irq = 0, stolen = 0;
            user = CPCSysUtil::Tick2MescAndNext(ptr);
            nice = CPCSysUtil::Tick2MescAndNext(ptr);
            sys = CPCSysUtil::Tick2MescAndNext(ptr);
            idle = CPCSysUtil::Tick2MescAndNext(ptr);
            if (*ptr == ' ')
            {
                // 2.6+ kernels 
                wait = CPCSysUtil::Tick2MescAndNext(ptr);
                irq = CPCSysUtil::Tick2MescAndNext(ptr);
                soft_irq = CPCSysUtil::Tick2MescAndNext(ptr);
            }
            if (*ptr == ' ')
            {
                // 2.6.11+ kernels 
                stolen = CPCSysUtil::Tick2MescAndNext(ptr);
            }
            tmp.user = user + nice;
            tmp.idle = idle;
            tmp.sys = sys;
            tmp.total = user + nice + sys + idle + wait + irq + soft_irq + stolen;
            if (tmp.total == 0) tmp.total = 1;

            vecCpuInfo.push_back(tmp);
        }
        if (vecCpuInfo.size() != cpucount)
        {
            return result.SetFail("read cpu count %d != cpucount %d", (int)vecCpuInfo.size(), cpucount);
        }

        //获取cpu基本信息
        ret = CPCFileUtil::PCReadFileLines("/proc/cpuinfo");
        int curr_cpu = 0;
        for (size_t i = 0; i < ret.size(); i++)
        {
            if (ret[i].empty())
            {
                curr_cpu++;
                if (curr_cpu >= cpucount)
                    break;
                continue;
            }

            const char* line = ret[i].c_str();
            switch (line[0])
            {
            case 'V':
            case 'v':
                if (CPCStrUtil::PCStrIsStartWith(line, "vendor", true))
                {
                    vecCpuInfo[curr_cpu].vendor = CPCStrUtil::PCStrGetFlagAfter(line, ":");
                }
                break;
            case 'M':
            case 'm':
                if (CPCStrUtil::PCStrIsStartWith(line, "model name", true))
                {
                    vecCpuInfo[curr_cpu].name = CPCStrUtil::PCStrGetFlagAfter(line, ":");
                }
                break;
            case 'C':
            case 'c':
                if (CPCStrUtil::PCStrIsStartWith(line, "cpu MHz", true))
                {
                    std::string strMHz = CPCStrUtil::PCStrGetFlagAfter(line, ":");
                    vecCpuInfo[curr_cpu].mhz = atoi(strMHz.c_str());
                }
                break;
            default:
                break;
            }
        }
#endif
        return result;
    }

    /**
    *@brief     取内存信息
    *@param     stMemInfo    [out]    内存信息
    *@return    是否成功
    */
    static CPCResult<> GetMemInfo(PCMEMINFO& stMemInfo)
    {
        CPCResult<> result;
#if defined(PCOS_WIN)
        MEMORYSTATUSEX memory_status;
        memory_status.dwLength = sizeof(memory_status);
        if (!GlobalMemoryStatusEx(&memory_status))
        {
            return result.SetSystemFail();
        }
        stMemInfo.total = memory_status.ullTotalPhys;
        stMemInfo.free = memory_status.ullAvailPhys;
        stMemInfo.used = stMemInfo.total - stMemInfo.free;
        stMemInfo.swaptotal = memory_status.ullTotalPageFile;
        stMemInfo.swapfree = memory_status.ullAvailPageFile;
        stMemInfo.swapused = stMemInfo.swaptotal - stMemInfo.swapfree;
#else
        stMemInfo.total = 0;
        stMemInfo.free = 0;
        stMemInfo.used = 0;
        stMemInfo.swaptotal = 0;
        stMemInfo.swapfree = 0;
        stMemInfo.swapused = 0;
        std::vector<std::string> ret = CPCFileUtil::PCReadFileLines("/proc/meminfo");
        if (ret.size() < 3)
        {
            return result.SetSystemFail();
        }
        for (size_t i = 0; i < ret.size(); i++)
        {
            const char* line = ret[i].c_str();
            switch (line[0])
            {
            case 'M':
            case 'm':
                if (CPCStrUtil::PCStrIsStartWith(line, "MemTotal", true))
                {
                    std::string memtotal = CPCStrUtil::PCStrGetFlagAfter(line, ":");
                    stMemInfo.total = CPCStrUtil::PCSizeDescToBytes(memtotal.c_str());
                }
                else if (CPCStrUtil::PCStrIsStartWith(line, "MemFree", true))
                {
                    std::string memfree = CPCStrUtil::PCStrGetFlagAfter(line, ":");
                    stMemInfo.free = CPCStrUtil::PCSizeDescToBytes(memfree.c_str());
                }
                break;
            case 'S':
            case 's':
                if (CPCStrUtil::PCStrIsStartWith(line, "SwapTotal", true))
                {
                    std::string swaptotal = CPCStrUtil::PCStrGetFlagAfter(line, ":");
                    stMemInfo.swaptotal = CPCStrUtil::PCSizeDescToBytes(swaptotal.c_str());
                }
                else if (CPCStrUtil::PCStrIsStartWith(line, "SwapFree", true))
                {
                    std::string swapfree = CPCStrUtil::PCStrGetFlagAfter(line, ":");
                    stMemInfo.swapfree = CPCStrUtil::PCSizeDescToBytes(swapfree.c_str());
                }
                break;
            default:
                break;
            }
        }
        stMemInfo.used = stMemInfo.total - stMemInfo.free;
        stMemInfo.swapused = stMemInfo.swaptotal - stMemInfo.swapfree;
#endif
        return result;
    }

    /**
    *@brief     取系统信息
    *@param     stSysInfo    [out]    系统信息
    *@return    是否成功
    */
    static CPCResult<> GetSystemInfo(PCSYSTEMINFO& stSysInfo)
    {
        CPCResult<> result;
#if defined(PCOS_WIN)
        PCWIN_USE_API(NTDLL,RtlGetNtVersionNumbers);
        DWORD dwBuildNumber = 0;
        PC_RtlGetNtVersionNumbers((DWORD*)&stSysInfo.os_version_major, (DWORD*)&stSysInfo.os_version_minor, &dwBuildNumber);
        if(!PC_RtlGetNtVersionNumbers)
        {
            return result.SetSystemFail();
        }
        if (stSysInfo.os_version_major == 6 && stSysInfo.os_version_minor == 3)
        {
            stSysInfo.os_name = "Windows 8.1";
        }
        else if (stSysInfo.os_version_major == 10 && stSysInfo.os_version_minor == 0)
        {
            stSysInfo.os_name = "Windows 10";
        }
        else
        {
            OSVERSIONINFOEXA version;
            version.dwOSVersionInfoSize = sizeof(version);
            if (!GetVersionExA((OSVERSIONINFOA *)&version))
            {
                return result.SetSystemFail();
            }
            stSysInfo.os_version_major = (int)version.dwMajorVersion;
            stSysInfo.os_version_minor = (int)version.dwMinorVersion;
            if (version.dwMajorVersion == 4)
            {
                stSysInfo.os_name = "Windows NT";
            }
            else if (version.dwMajorVersion == 5)
            {
                switch (version.dwMinorVersion)
                {
                case 0:
                    stSysInfo.os_name = "Windows 2000";
                    break;
                case 1:
                    stSysInfo.os_name = "Windows XP";
                    break;
                case 2:
                    stSysInfo.os_name = "Windows 2003";
                    break;
                default:
                    stSysInfo.os_name = "Windows Unknown";
                    break;
                }
            }
            else if (version.dwMajorVersion == 6)
            {
                if (version.wProductType == VER_NT_WORKSTATION)
                {
                    if (version.dwMinorVersion == 0)
                    {
                        stSysInfo.os_name = "Windows Vista";
                    }
                    else
                    {
                        stSysInfo.os_name = "Windows 7";
                    }
                }
                else
                {
                    // not nt work station
                    if (version.dwMinorVersion == 0 || version.dwMinorVersion == 1)
                    {
                        stSysInfo.os_name = "Windows Server 2008";
                    }
                    else if (version.dwMinorVersion == 2 || version.dwMinorVersion == 3)
                    {
                        stSysInfo.os_name = "Windows Server 2012";
                    }
                    else
                    {
                        // defaults
                        stSysInfo.os_name = "Windows Server Unknown";
                    }
                }
            }
            else
            {
                stSysInfo.os_name = "Windows Unknown";
            }
        }

        SYSTEM_INFO si;
        ::GetNativeSystemInfo(&si);
        stSysInfo.pagesize = (unsigned int)si.dwPageSize;
        stSysInfo.is64bit = false;
        switch (si.wProcessorArchitecture)
        {
        case PROCESSOR_ARCHITECTURE_INTEL:
            stSysInfo.arch_name = "INTEL";
            break;
        case PROCESSOR_ARCHITECTURE_MIPS:
            stSysInfo.arch_name = "MIPS";
            break;
        case PROCESSOR_ARCHITECTURE_ALPHA:
            stSysInfo.arch_name = "ALPHA";
            break;
        case PROCESSOR_ARCHITECTURE_PPC:
            stSysInfo.arch_name = "PPC";
            break;
        case PROCESSOR_ARCHITECTURE_SHX:
            stSysInfo.arch_name = "SHX";
            break;
        case PROCESSOR_ARCHITECTURE_ARM:
            stSysInfo.arch_name = "ARM";
            break;
        case PROCESSOR_ARCHITECTURE_IA64:
            stSysInfo.arch_name = "IA64";
            stSysInfo.is64bit = true;
            break;
        case PROCESSOR_ARCHITECTURE_ALPHA64:
            stSysInfo.arch_name = "ALPHA64";
            break;
        case PROCESSOR_ARCHITECTURE_MSIL:
            stSysInfo.arch_name = "MSIL";
            break;
        case PROCESSOR_ARCHITECTURE_AMD64:
            stSysInfo.arch_name = "AMD64";
            stSysInfo.is64bit = true;
            break;
        case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64:
            stSysInfo.arch_name = "IA32_ON_WIN64";
            break;
        default:
            stSysInfo.arch_name = CPCStrUtil::UIntToString(si.wProcessorArchitecture);
            break;
        }
#else
        struct utsname name;
        if (uname(&name) != 0)
        {
            return result.SetSystemFail();
        }
        stSysInfo.os_version_major = 0;
        stSysInfo.os_version_minor = 0;
        stSysInfo.os_name = name.sysname;
        stSysInfo.os_name.append("|");
        stSysInfo.os_name.append(name.nodename);
        stSysInfo.os_name.append("|");
        stSysInfo.os_name.append(name.version);
        stSysInfo.arch_name = name.machine;
        stSysInfo.pagesize = getpagesize();
        stSysInfo.is64bit = (strstr(name.machine, "64") || strstr(name.machine, "686"));
#endif
#if defined(PCOS_ANDROID)
        char szDevId[MAX_PATH] = { 0 };
        memset(szDevId, 0, sizeof(szDevId));
        __system_property_get("ro.serialno", szDevId);
        stSysInfo.os_name.append("|serialno:");
        stSysInfo.os_name.append(szDevId);

        memset(szDevId, 0, sizeof(szDevId));
        __system_property_get("ro.product.model", szDevId);
        stSysInfo.os_name.append("|model:");
        stSysInfo.os_name.append(szDevId);

        memset(szDevId, 0, sizeof(szDevId));
        __system_property_get("ro.build.version.sdk", szDevId);
        stSysInfo.os_name.append("|sdk:");
        stSysInfo.os_name.append(szDevId);

        stSysInfo.os_name.append("|Android");
#endif
        return result;
    }

    /**
    *@brief     取文件系统信息
    *@param     stFSInfo    [out]    文件系统信息
    *@return    是否成功
    */
    static CPCResult<> GetFileSystemInfo(std::vector<PCFSINFO>& vecFSInfo)
    {
        CPCResult<> result;
        vecFSInfo.clear();
#if defined(PCOS_WIN)
        char name[MAX_PATH];
        DWORD len = GetLogicalDriveStringsA(sizeof(name), name);
        if (len == 0 || len > sizeof(name))
        {
            return result.SetSystemFail();
        }
        char* nameptr = name;
        while (*nameptr)
        {
            PCFSINFO disktmp;
            disktmp.name = nameptr;
            unsigned int drive_type = GetDriveTypeA(nameptr);
            switch (drive_type)
            {
            case DRIVE_FIXED:
                disktmp.dev_type = "DRIVE_FIXED";
                break;
            case DRIVE_REMOTE:
                disktmp.dev_type = "DRIVE_REMOTE";
                break;
            case DRIVE_CDROM:
                disktmp.dev_type = "DRIVE_CDROM";
                break;
            case DRIVE_RAMDISK:
                disktmp.dev_type = "DRIVE_RAMDISK";
                break;
            case DRIVE_REMOVABLE:
                disktmp.dev_type = "DRIVE_REMOVABLE";
                break;
            default:
                disktmp.dev_type = "UNKNOWN";
                break;
            }
            DWORD flags = 0, serialnum = 0;
            char szFsName[MAX_PATH] = { 0 };
            if (GetVolumeInformationA(nameptr, NULL, 0, &serialnum, NULL, &flags, szFsName, sizeof(szFsName)))
            {
                disktmp.fs_type = szFsName;
            }
            else
            {
                disktmp.fs_type = "UNKNOWN";
            }

            //prevent dialog box if A: drive is empty 
            SetErrorMode(SEM_FAILCRITICALERRORS);

            ULARGE_INTEGER avail, total, free;
            if (GetDiskFreeSpaceExA(nameptr, &avail, &total, &free))
            {
                disktmp.total = total.QuadPart;
                disktmp.free = free.QuadPart;
                disktmp.used = disktmp.total - disktmp.free;
            }
            else
            {
                disktmp.total = 0;
                disktmp.free = 0;
                disktmp.used = 0;
            }

            vecFSInfo.push_back(disktmp);
            nameptr += strlen(nameptr) + 1;
        }
#elif defined(PCOS_LINUX)
        FILE *fp = setmntent(MOUNTED, "r");
        if (fp == NULL)
        {
            return result.SetSystemFail();
        }

        int lastError = 0;
        struct mntent ent;
        CPCBuffer buf(PC_MAXURL);
        while (getmntent_r(fp, &ent, buf.data(), buf.capacity()))
        {
            struct statvfs stvfs;
            if (::statvfs(ent.mnt_dir, &stvfs) != 0)
            {
                lastError = PCGetLastError();
                continue;
            }
            if (stvfs.f_blocks == 0)
                continue;
            PCFSINFO disktmp;
            disktmp.name = ent.mnt_dir;
            disktmp.dev_type = ent.mnt_fsname;
            disktmp.fs_type = ent.mnt_type;

            disktmp.total = (uint64_t)stvfs.f_blocks * (uint64_t)stvfs.f_bsize;
            disktmp.free = (uint64_t)stvfs.f_bfree * (uint64_t)stvfs.f_bsize;
            disktmp.used = disktmp.total - disktmp.free;

            vecFSInfo.push_back(disktmp);
        }
        endmntent(fp);

        if (vecFSInfo.empty())
        {
            if (lastError == 0)
                lastError = PCGetLastError();
            return result.SetSystemFail(lastError);
        }
#else 
        //macos
        int num = 0;
        if ((num = getfsstat(NULL, 0, MNT_NOWAIT)) < 0)
        {
            return result.SetSystemFail();
        }
        int len = sizeof(struct statfs) * num;
        struct statfs *fs = (struct statfs *)malloc(len);
        if (fs == NULL)
        {
            return result.SetSystemFail();
        }
        CPCAutoObj autoFree([&fs](){free(fs); });

        if ((num = getfsstat(fs, len, MNT_NOWAIT)) < 0)
        {
            return result.SetSystemFail();
        }

        int lastError = 0;
        for (int i = 0; i < num; i++)
        {
#ifdef MNT_AUTOMOUNTED
            if (fs[i].f_flags & MNT_AUTOMOUNTED)
                continue;
#endif
#ifdef MNT_RDONLY
            if (fs[i].f_flags & MNT_RDONLY)
                continue;
#endif
            struct statvfs stvfs;
            if (::statvfs(fs[i].f_mntonname, &stvfs) != 0)
            {
                lastError = PCGetLastError();
                continue;
            }
            if (stvfs.f_blocks == 0)
                continue;
            PCFSINFO disktmp;
            disktmp.name = fs[i].f_mntonname;
            disktmp.dev_type = fs[i].f_mntfromname;
            disktmp.fs_type = fs[i].f_fstypename;

            disktmp.total = (uint64_t)stvfs.f_blocks * (uint64_t)stvfs.f_bsize;
            disktmp.free = (uint64_t)stvfs.f_bfree * (uint64_t)stvfs.f_bsize;
            disktmp.used = disktmp.total - disktmp.free;

            vecFSInfo.push_back(disktmp);
        }
        if (vecFSInfo.empty())
        {
            if (lastError == 0)
                lastError = PCGetLastError();
            return result.SetSystemFail(lastError);
        }
#endif
        return result;
    }

    /**
    *@brief     取进程信息，使用前要求初始化COM。可以在main函数第一句调用CPCDCOMInit initCom;
    *@param     stSysInfo    [out]    系统信息
    *@return    是否成功
    */
    static CPCResult<> PCGetProcInfo(std::vector<PCPROCESSINFO>& vecProcInfo)
    {
        CPCResult<> result;
        vecProcInfo.clear();
        PCSYSTEMINFO stSysInfo;

        result = CPCSysUtil::GetSystemInfo(stSysInfo);
        if (!result)
            return result;
        bool bSys64Bit = stSysInfo.is64bit;
        unsigned int pagesz = stSysInfo.pagesize;
#if defined(PCOS_WIN)
        CPCPrivilege::Adjust(SE_DEBUG_NAME);

        HANDLE handle = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
        if (handle == INVALID_HANDLE_VALUE)
        {
            return result.SetSystemFail();
        }
        CPCAutoObj autoHandle([&handle](){PCCloseHandle(handle); });

        PROCESSENTRY32 pe;
        pe.dwSize = sizeof(PROCESSENTRY32);
        if (!::Process32First(handle, &pe))
        {
            return result.SetSystemFail();
        }

        CPCWMIHandle wmi;
        result = wmi.Open();
        if (!result)
            return result;
        while (::Process32Next(handle, &pe))
        {
            PCPROCESSINFO proctmp;
            proctmp.cpu_usage = 0;
#ifdef UNICODE
            CPCConvertHelper::PCW2A(proctmp.name, pe.szExeFile);
#else
            proctmp.name = pe.szExeFile;
#endif  // !UNICODE
            proctmp.pid = pe.th32ProcessID;
            proctmp.ppid = pe.th32ParentProcessID;
            proctmp.priclassbase = pe.pcPriClassBase;
            proctmp.threads = pe.cntThreads;

            //取内存信息
            PROCESS_MEMORY_COUNTERS stProcMemCnts;
            HANDLE hProcess = ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, proctmp.pid);
            if (hProcess && ::GetProcessMemoryInfo(hProcess, &stProcMemCnts, sizeof(stProcMemCnts)))
            {
                proctmp.mem_pagefile = stProcMemCnts.PagefileUsage;
                proctmp.mem_workingset = stProcMemCnts.WorkingSetSize;
            }
            else
            {
                proctmp.mem_pagefile = 0;
                proctmp.mem_workingset = 0;
            }

            //位数
            proctmp.is64bit = bSys64Bit;
            BOOL bWow64Process = !bSys64Bit;
            if (bSys64Bit && hProcess && ::IsWow64Process(hProcess, &bWow64Process))
            {
                proctmp.is64bit = !bWow64Process;
            }

            //cpu
            FILETIME start_time, exit_time;
            if (hProcess && ::GetProcessTimes(hProcess, &start_time, &exit_time, (LPFILETIME)&proctmp.cpu_sys, (LPFILETIME)&proctmp.cpu_user))
            {
                proctmp.cpu_sys = proctmp.cpu_sys / 10000;
                proctmp.cpu_user = proctmp.cpu_user / 10000;
                proctmp.cpu_total = proctmp.cpu_sys + proctmp.cpu_user;
            }
            else
            {
                proctmp.cpu_sys = 0;
                proctmp.cpu_user = 0;
                proctmp.cpu_total = 0;
            }
            PCCloseHandle(hProcess);

            //取cmdline
            auto result2 = wmi.GetProcPropertyString(proctmp.pid, L"CommandLine");
            if (result2)
            {
                proctmp.cmdline = result2.Get();
            }
            vecProcInfo.push_back(proctmp);
        }

        //让wmi退出作用域自动析构好像会有问题
        wmi.Close();
#else
        CPCBuffer buffer(PC_MAXSTACK);
        result = CPCFileUtil::PCScanDir("/proc/", [&vecProcInfo, &buffer, &bSys64Bit, &pagesz](const char* pszPath, const char* pszFileName, bool bDir)->CPCResult<>
        {
            CPCResult<> resin;
            if (!bDir)
                return resin;
            if (pszFileName[0] < '0' || pszFileName[0] > '9')
                return resin;

            PCPROCESSINFO proctmp;
            proctmp.cpu_usage = 0;
            proctmp.threads = 0;
            proctmp.pid = atoi(pszFileName);

            //cpu info
            std::string path = "/proc/";
            path += pszFileName;
            path += "/stat";
            auto result2 = CPCFileUtil::PCReadFile(path.c_str(), (unsigned char*)buffer.data(), buffer.capacity());
            if (!result2)
            {
                return resin.SetSucc();
            }
            buffer.updatesize(result2.Get());
            std::vector<std::string> ret = CPCStrUtil::PCStrSplit(buffer.c_str(), "\t ");
            if (ret.size() < 20 || ret[1].length() < 3)
            {
                return resin;
            }

            proctmp.name.assign(ret[1].data() + 1, ret[1].length() - 2);
            proctmp.ppid = atoi(ret[3].c_str());
            proctmp.priclassbase = atoi(ret[18].c_str());
            proctmp.is64bit = bSys64Bit;    //TODO:too simple

            proctmp.cpu_user = CPCStrUtil::StringToUInt64(ret[13].c_str());
            proctmp.cpu_sys = CPCStrUtil::StringToUInt64(ret[14].c_str());
            proctmp.cpu_total = proctmp.cpu_sys + proctmp.cpu_user;

            //cmdline
            path = "/proc/";
            path += pszFileName;
            path += "/cmdline";
            result2 = CPCFileUtil::PCReadFile(path.c_str(), (unsigned char*)buffer.data(), buffer.capacity());
            if (result2)
            {
                //cmdline 原始数据使用 \0 分隔，这里要处理一下.
                const char* pCmdLine = buffer.data();
                proctmp.cmdline.clear();
                for (int i = 0; i < result2.Get(); i++)
                {
                    if (pCmdLine[i] == 0)
                        proctmp.cmdline.push_back(' ');
                    else
                        proctmp.cmdline.push_back(pCmdLine[i]);
                }
            }

            //mem info
            path = "/proc/";
            path += pszFileName;
            path += "/statm";
            result2 = CPCFileUtil::PCReadFile(path.c_str(), (unsigned char*)buffer.data(), buffer.capacity());
            if (!result2)
            {
                return resin.SetSucc();
            }
            buffer.updatesize(result2.Get());
            ret = CPCStrUtil::PCStrSplit(buffer.c_str(), "\t ");
            if (ret.size() < 2)
            {
                return resin;
            }
            proctmp.mem_pagefile = pagesz*(CPCStrUtil::StringToUInt64(ret[0].c_str()));
            proctmp.mem_workingset = pagesz*(CPCStrUtil::StringToUInt64(ret[1].c_str()));

            //threads
            path = "/proc/";
            path += pszFileName;
            path += "/status";
            ret = CPCFileUtil::PCReadFileLines(path.c_str());
            if (ret.size() < 3)
            {
                return resin.SetSucc();
            }
            for (size_t i = 0; i < ret.size(); i++)
            {
                const char* line = ret[i].c_str();
                switch (line[0])
                {
                case 'T':
                case 't':
                    if (CPCStrUtil::PCStrIsStartWith(line, "Threads", true))
                    {
                        std::string threadsstr = CPCStrUtil::PCStrGetFlagAfter(line, ":");
                        proctmp.threads = atoi(threadsstr.c_str());
                    }
                    break;
                default:
                    break;
                }
            }
            vecProcInfo.push_back(proctmp);
            return resin;
        });
#endif
        if (!vecProcInfo.empty())
            result.SetSucc();
        return result;
    }

    /**
    *@brief     获取操作系统当前登录的用户名
    *@return    成功：std::string[用户名]    
    */
    static CPCResult<std::string> PCGetLoginUser()
    {
        CPCResult<std::string> result;
        char szLoginName[MAX_PATH+1];
        memset(szLoginName, 0, sizeof(szLoginName));
#if defined(PCOS_WIN) 
        DWORD dwLoginSize = MAX_PATH;
        if (!::GetUserNameA(szLoginName, &dwLoginSize))
        {
            return result.SetSystemFail();
        }
#else
        char * loginname = getlogin();
        if (loginname == NULL || strlen(loginname) >= sizeof(szLoginName))
        {
            return result.SetSystemFail();
        }
        strcpy(szLoginName, loginname);
#endif
        return result.SetSucc(szLoginName);
    }

    /**
    *@brief     获取计算机名
    *@return    成功：std::string[用户名]    
    */
    static CPCResult<std::string> PCGetComputerName()
    {
        CPCResult<std::string> result;
        char szComputerName[MAX_PATH+1];
        memset(szComputerName, 0, sizeof(szComputerName));
#if defined(PCOS_WIN) 
        DWORD nSize = MAX_PATH;
        if (!::GetComputerNameA(szComputerName, &nSize))
        {
            return result.SetSystemFail();
        }
#else
        if (0 != ::gethostname(szComputerName,MAX_PATH))
        {
            return result.SetSystemFail();
        }
#endif
        return result.SetSucc(szComputerName);
    }

    /**
    *@brief     关机和重启
    *@param     bReboot    [in]    true重启，false关机。
    *@return    成功：CPCResult.Succ    失败：CPCResult.ErrDesc[错误描述]
    */
    static CPCResult<> PCShutdown(bool bReboot = false)
    {
        CPCResult<> result;
#if defined(PCOS_WIN) 
        result = CPCPrivilege::Adjust(SE_SHUTDOWN_NAME);
        if (!result)
        {
            return result;
        }
        if (!bReboot)
        {
            if (!::ExitWindowsEx(EWX_SHUTDOWN | EWX_POWEROFF | EWX_FORCE, 0))
            {
                return result.SetSystemFail();
            }
        }
        else
        {
            if (!::ExitWindowsEx(EWX_REBOOT | EWX_FORCE, 0))
            {
                return result.SetSystemFail();
            }
        }
        return result;
#else
        return CPCSysUtil::PCSystemCmd(bReboot ? PC_CMD_REBOOT : PC_CMD_SHUTDOWN);
#endif
    }


    /**
    *@brief     执行系统命令
    *@param     pszCmd    [in]    命令。
    *@return    成功：CPCResult.Succ    失败：CPCResult.ErrDesc[错误描述]
    */
    static CPCResult<> PCSystemCmd(const char* pszCmd)
    {
        CPCResult<> result;
#if !defined(PCOS_IOS)         
        if (pszCmd == NULL || pszCmd[0] == 0)
        {
            return result.SetFail("params err.pszCmd:empty.");
        }

        if (system(pszCmd) != 0)
        {
            return result.SetSystemFail();
        }
        return result;
#else
        return result.SetFail("unsupported");
#endif
    }

    /**
    *@brief     执行系统命令并等待且获取结果
    *@param     pszCmd    [in]    命令。
    *@param     funcRet   [in]    取结果的回调函数。
    *@return    是否成功。成功则std::string为命令结果
    */
    static CPCResult<std::string> PCSystemCmdAndWait(const char* pszCmd, std::function<void(const char* ret)> funcRet)
    {
        CPCResult<std::string> result;
        std::string resultbuf = "";
#if defined (PCOS_WIN)
        std::string csCmdLine = "cmd.exe /c  \"";
        csCmdLine = csCmdLine + pszCmd;
        csCmdLine = csCmdLine + "\"";

        //创建匿名管道，用于接收指令执行后的数据
        HANDLE hRead = NULL, hWrite = NULL;
        SECURITY_ATTRIBUTES sa;
        sa.nLength = sizeof(SECURITY_ATTRIBUTES);
        sa.lpSecurityDescriptor = NULL;
        sa.bInheritHandle = TRUE;
        if (!CreatePipe(&hRead, &hWrite, &sa, 0))
        {
            return result.SetSystemFail();
        }

        //根据命令创建子进程，并修改子进程的stderr/stdout为上面创建的匿名管道一端（write端）
        STARTUPINFOA si;
        ZeroMemory(&si, sizeof(STARTUPINFOA));
        si.cb = sizeof(STARTUPINFOA);
        GetStartupInfoA(&si);
        si.hStdError = hWrite;
        si.hStdOutput = hWrite;
        si.wShowWindow = SW_HIDE;
        si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
        PROCESS_INFORMATION pi;
        if (!CreateProcessA(NULL, (LPSTR)csCmdLine.c_str(), NULL, NULL, TRUE, NULL, NULL, NULL, &si, &pi))
        {
            CloseHandle(hWrite);
            CloseHandle(hRead);
            return result.SetSystemFail();
        }
        CloseHandle(hWrite);

        //从匿名管道read端读取数据
        DWORD	allBufLen = 0;
        while (true)
        {
            char buffer[4096] = { 0 };
            memset(buffer, 0, sizeof(buffer));

            //读取管道，进程结束后ReadFile才会返回FALSE
            DWORD bytesRead;
            if (!ReadFile(hRead, buffer, 4095, &bytesRead, NULL))
            {
                break;
            }
            if (funcRet)
                funcRet(buffer);
            resultbuf = resultbuf + buffer;
            allBufLen += bytesRead;
        }
        CloseHandle(hRead);
#else
        char buf_ps[1024] = { 0 };
        FILE *ptr = popen(pszCmd, "r");
        if (ptr == NULL)
        {
            return result.SetSystemFail();
        }
        while (fgets(buf_ps, sizeof(buf_ps) - 1, ptr) != NULL)
        {
            resultbuf = resultbuf + buf_ps;
            if (funcRet)
                funcRet(buf_ps);
            memset(buf_ps, 0, sizeof(buf_ps));
        }
        pclose(ptr);
        ptr = NULL;
#endif
        return result.SetSucc(std::move(resultbuf));
    }

    /**
    *@brief     执行系统命令且等待并获取结果
    *@param     pszCmd    [in]    命令。
    *@return    是否成功，成功后，结果为std::string
    */
    static CPCResult<std::string> PCSystemCmdWait(const char* pszCmd)
    {
        CPCResult<std::string> result;
        if (pszCmd == NULL || pszCmd[0] == 0)
        {
            return result.SetFail("params err.pszCmd:empty.");
        }
#if defined(PCOS_WIN) 
        //创建匿名管道，用于接收指令执行后的数据
        HANDLE hRead = NULL;
        HANDLE hWrite = NULL;
        SECURITY_ATTRIBUTES sa;
        sa.nLength = sizeof(SECURITY_ATTRIBUTES);
        sa.lpSecurityDescriptor = NULL;
        sa.bInheritHandle = TRUE;
        if (!CreatePipe(&hRead, &hWrite, &sa, 0))
        {
            return result.SetSystemFail();
        }
        CPCAutoObj autoCloseRead([&hRead](){PCCloseHandle(hRead); });
        CPCAutoObj autoCloseWrite([&hWrite](){PCCloseHandle(hWrite); });

        //根据命令创建子进程，并修改子进程的stderr/stdout为上面创建的匿名管道一端(write端)
        STARTUPINFOA si;
        ZeroMemory(&si, sizeof(STARTUPINFOA));
        si.cb = sizeof(STARTUPINFOA);
        GetStartupInfoA(&si);
        si.hStdError = hWrite;
        si.hStdOutput = hWrite;
        si.wShowWindow = SW_HIDE;
        si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
        PROCESS_INFORMATION pi;
        std::string cmdinfo = "CMD.exe /C ";
        cmdinfo += pszCmd;
        if (!CreateProcessA(NULL, (char*)cmdinfo.c_str(), NULL, NULL, TRUE, NULL, NULL, NULL, &si, &pi))
        {
            return result.SetSystemFail();
        }
        PCCloseHandle(hWrite);
#else
        FILE *pfp = ::popen(pszCmd, "r");
        if (pfp == NULL)
        {
            return result.SetSystemFail();
        }
        CPCAutoObj autoClose([&pfp](){pclose(pfp); });
#endif
        //接受结果
        char buffer[1024];
        while (1)
        {
            memset(buffer, 0, sizeof(buffer));
#if defined(PCOS_WIN)
            DWORD bytesRead = 0;
            if (::ReadFile(hRead, buffer, sizeof(buffer) - 1, &bytesRead, NULL))
            {
                result.Get().append(buffer, bytesRead);
                continue;
            }
#else
            if (::fgets(buffer, sizeof(buffer) - 1, pfp))
            {
                result.Get().append(buffer);
                continue;
            }
#endif
            break;
        }
        return result;
    }

    /**
    *@brief     回到桌面
    *@return    成功：CPCResult.Succ    失败：CPCResult.ErrDesc[错误描述]
    */
    static CPCResult<> PCDisplayDesktop()
    {
        CPCResult<> result;
#if defined(PCOS_WIN) 
        CoInitialize(0);

        IShellDispatch4 * pdisp = NULL;
        HRESULT hrResult = CoCreateInstance(CLSID_Shell, NULL, CLSCTX_ALL, __uuidof(IShellDispatch4), (void **)&pdisp);
        if (FAILED(hrResult))
        {
            CoUninitialize();
            return result.SetSystemFail();
        }

        hrResult = pdisp->ToggleDesktop();
        pdisp->Release();
        CoUninitialize();
        if (FAILED(hrResult))
        {
            return result.SetSystemFail();
        }
#else
        result.SetFail("unsupported.");
#endif
        return result;
    }

    /**
    *@brief     控制任务栏(暂时只支持windows)
    *@param     bTrayShow        [in]    隐藏或显示任务栏
    *@param     bDesktopIconShow [in]    隐藏或显示桌面图标，TODO 我的机器上有点问题无法隐藏
    *@return    成功：CPCResult.Succ    失败：CPCResult.ErrDesc[错误描述]
    */
    static CPCResult<> PCControlTaskPanel(bool bTrayShow, bool bDesktopIconShow)
    {
        CPCResult<> result;
#if defined(PCOS_WIN) 
        HWND hWndTray = ::FindWindowA("Shell_traywnd", "");
        if (NULL == hWndTray)
            return result.SetSystemFail();
        HWND hWndProgMan = ::FindWindowA("ProgMan", NULL);
        if (NULL == hWndProgMan)
            return result.SetSystemFail();

        //执行后窗口可见，返回非0值，执行后窗口不可见，返回0
        ShowWindow(hWndTray, bTrayShow ? SW_SHOW : SW_HIDE);
        ShowWindow(hWndProgMan, bDesktopIconShow ? SW_SHOW : SW_HIDE);
#else
        result.SetFail("unsupported.");
#endif
        return result;
    }

    /**
    *@brief     返回屏幕信息，最大支持屏幕个数为260(暂时只支持windows)
    *@return    是否成功
    */
    static CPCResult<> PCGetScrrenInfo(std::vector<PCSCREENINFO> &vecInfo)
    {
        CPCResult<> result;
        vecInfo.clear();
#if defined(PCOS_WIN)
        for (int i = 0; i < MAX_PATH; i++)
        {
            //注册表中的屏幕信息
            DISPLAY_DEVICEA dd;
            ZeroMemory(&dd, sizeof(dd));
            dd.cb = sizeof(dd);
            BOOL bSucc = EnumDisplayDevicesA(NULL, i, &dd, 0);
            if (!bSucc)
            {
                break;
            }

            //可用屏幕信息
            DEVMODEA devMode;
            ZeroMemory(&devMode, sizeof(devMode));
            devMode.dmSize = sizeof(devMode);
            bSucc = EnumDisplaySettingsA(dd.DeviceName, ENUM_CURRENT_SETTINGS, &devMode);
            if (!bSucc)
            {
                continue;
            }

            PCSCREENINFO info;
            info.main = false;

            //判断是不是主屏
            POINT pt = { devMode.dmPosition.x, devMode.dmPosition.y };
            HMONITOR  monitor = MonitorFromPoint(pt, MONITOR_DEFAULTTONULL);
            if (monitor)
            {
                MONITORINFO mi;
                memset(&mi, 0, sizeof(MONITORINFO));
                mi.cbSize = sizeof(MONITORINFO);
                if (GetMonitorInfo(monitor, &mi) && mi.dwFlags == MONITORINFOF_PRIMARY)
                {
                    info.main = true;
                }
            }

            strcpy(info.name, dd.DeviceName);
            strcpy(info.model, dd.DeviceString);
            info.id = i + 1;

            info.left = devMode.dmPosition.x;
            info.top = devMode.dmPosition.y;
            info.width = devMode.dmPelsWidth;
            info.height = devMode.dmPelsHeight;

            vecInfo.push_back(info);
        }
#elif defined(PCOS_ANDROID)
        auto result2 = CPCSysUtil::PCSystemCmdWait("wm size");
        if (!result2)
        {
            return result.SetFail("PCSystemCmdWait fail:%s",result2.ErrDesc());
        }
        std::string content = result2.Take();//("Physical size: 1080x2340\n");
        std::regex pattern("[^\\d]*(\\d+)x(\\d+)[^\\d]*");
        std::smatch matchres;
        if (!std::regex_search(content.cbegin(), content.cend(), matchres, pattern) || matchres.size() != 3)
        {
            return result.SetFail("not find info. %s", content.c_str());
        }
        PCSCREENINFO info;
        info.main = true;
        info.id = 1;
        info.left = 0;
        info.top = 0;
        info.width = atoi(matchres[1].str().c_str());
        info.height = atoi(matchres[2].str().c_str());
        vecInfo.push_back(info);
#elif defined(PCOS_LINUX) && !defined(QT_VERSION)
        //need link xcb
        /*
        int screen_number = 0;
        xcb_connection_t *xcbconn = xcb_connect(NULL, &screen_number);
        CPCAutoObj autoDiscon([&xcbconn](){xcb_disconnect(xcbconn);});
        int err = xcb_connection_has_error(xcbconn);
        if(err != 0)
        {
        return result.SetFail("xcb_connection_has_error:%d",err);
        }
        const xcb_setup_t *setup = xcb_get_setup(xcbconn);
        if(setup == NULL)
        {
        return result.SetFail("xcb_get_setup fail:%d\n",errno);
        }
        xcb_screen_t *screen = NULL;
        xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup);
        for(int id = 0 ;iter.rem!=0; xcb_screen_next(&iter), id++)
        {
        screen = iter.data;
        if(screen == NULL)
        break;

        PCSCREENINFO info;
        info.main = (id == 0);
        info.id = id;

        info.left = 0;
        info.top = 0;
        info.width = screen->width_in_pixels;
        info.height = screen->height_in_pixels;
        vecInfo.push_back(info);
        }
        */

        //need link X11
        Display *display = XOpenDisplay(NULL);
        if (NULL == display)
        {
            return result.SetFail("XOpenDisplay = NULL");
        }
        CPCAutoObj autoDiscon([&display](){XCloseDisplay(display); });

        int screencount = ScreenCount(display);
        int screendefalut = DefaultScreen(display);
        for (int i = 0; i < screencount; i++)
        {
            PCSCREENINFO info;
            info.main = (i == screendefalut);
            info.id = i;

            info.left = 0;
            info.top = 0;
            info.width = DisplayWidth(display, i);
            info.height = DisplayHeight(display, i);
            memset(info.name, 0x00, sizeof(info.name));
            memset(info.model, 0x00, sizeof(info.model));
            strncpy(info.name, DisplayString(display), sizeof(info.name));
            strncpy(info.model, ServerVendor(display), sizeof(info.model));

            vecInfo.push_back(info);
        }
#else
        result.SetFail("unsupported");
#endif
        return result;
    }

    /**
    *@brief    启动进程
    *@param    szPath          [in]    进程执行目录。
    *@param    szProcessName   [in]    进程名称。
    *@param    szParams        [in]    进程参数。
    *@param    bWait           [in]    是否等待进程结束。
    *@return   成功：CPCResult.Succ    失败：CPCResult.ErrDesc[错误描述]
    */
    static CPCResult<> PCStartProcess(const char* szPath, const char* szProcessName, const char* szParams, bool bWait)
    {
        CPCResult<> result;
        if (szPath == NULL || szProcessName == NULL || szProcessName[0] == 0
            || strlen(szPath) + strlen(szProcessName) >= MAX_PATH)
        {
            return result.SetFail("params invalid.");
        }
        std::string strParams = "";
        if (szParams != NULL)
        {
            strParams = szParams;
        }
#if defined(PCOS_WIN)
        CPCStrUtil::PCReplaceAll(strParams, "\"", "\"\"\"");
        //win10以下的ShellExecuteEx不支持正斜杠/
        char szRealPath[MAX_PATH + 2] = { 0 };
        memset(szRealPath, 0, sizeof(szRealPath));
        for (size_t i = 0; i < strlen(szPath); i++)
        {
            if (szPath[i] == '/')  szRealPath[i] = '\\';
            else szRealPath[i] = szPath[i];
        }

        SHELLEXECUTEINFOA  ShExecInfo = { 0 };
        ZeroMemory(&ShExecInfo, sizeof(SHELLEXECUTEINFO));
        ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
        ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI;
        ShExecInfo.hwnd = NULL;
        ShExecInfo.lpVerb = NULL;
        ShExecInfo.lpFile = szProcessName;
        ShExecInfo.lpParameters = strParams.c_str();
        ShExecInfo.lpDirectory = szRealPath;
        ShExecInfo.nShow = SW_HIDE;
        ShExecInfo.hInstApp = NULL;
        if (!ShellExecuteExA(&ShExecInfo))
        {
            return result.SetSystemFail();
        }
        if (bWait)
        {
            while (1)
            {
                DWORD dwWaitObj = WaitForSingleObject(ShExecInfo.hProcess, 100);
                if (WAIT_OBJECT_0 == dwWaitObj)
                {
                    break;
                }
                else if (WAIT_TIMEOUT == dwWaitObj)
                {
                    PCSleep(1000);
                    continue;
                }
                else
                {
                    return result.SetSystemFail();
                }
            }
        }
#else
        //在fork之前获取子进程绝对路径
        char szPathReal[MAX_PATH] = { 0 };
        strncpy(szPathReal, szPath, sizeof(szPathReal));
        CPCFileUtil::PCDirFormat(szPathReal);
        char szProcessFullPath[MAX_PATH] = { 0 };
        snprintf(szProcessFullPath, sizeof(szProcessFullPath), "%s%s", szPathReal, szProcessName);
        if (access(szProcessFullPath, F_OK) != 0)
        {
            return result.SetSystemFail();
        }
        pid_t childpid = fork();
        if (childpid < 0)
        {
            return result.SetSystemFail();
        }
        else if (childpid == 0)
        {
            //子进程，TODO：szParams应该解析成参数列表
            if (-1 == execl(szProcessFullPath, szProcessName, szParams, (char*)0))
            {
                return result.SetSystemFail();
            }
            exit(EXIT_SUCCESS);
        }
        else
        {
            //父进程
            if (bWait)
            {
                int nStatus = 0;
                if (-1 == waitpid(childpid, &nStatus, 0) || nStatus != 0)
                {
                    return result.SetSystemFail();
                }
            }
        }
#endif
        return result;
    }

    /**
    *@brief     根据进程名字获取进程pid
    *@param     szProcessName    [in]    进程名字
    *@return    是否成功，成功后pid保存在int
    */
    static CPCResult<int> PCGetPidByProcessName(const char* szProcessName)
    {
        CPCResult<int> result;
        if (szProcessName == NULL || szProcessName[0] == 0)
        {
            return result.SetFail("params invalid.");
        }
#if defined(PCOS_WIN)
        HANDLE handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
        if (handle == INVALID_HANDLE_VALUE)
        {
            return result.SetSystemFail();
        }
        CPCAutoObj autoHandle([&handle](){CloseHandle(handle); });

        PROCESSENTRY32 pe;
        pe.dwSize = sizeof(PROCESSENTRY32);
        if (!Process32First(handle, &pe))
        {
            return result.SetSystemFail();
        }
        while (Process32Next(handle, &pe))
        {
#ifdef UNICODE
            std::string strExeFile;
            CPCConvertHelper::PCW2A(strExeFile, pe.szExeFile);
            if (strcasecmp(strExeFile.c_str(), szProcessName) == 0)
#else
            if (strcasecmp(pe.szExeFile, szProcessName) == 0)
#endif  // !UNICODE
            {
                return result.SetSucc(pe.th32ProcessID);
            }
        }
        return result.SetFail("not find process:%s", szProcessName);
#else
        std::string findstr = "pgrep ";
        findstr += szProcessName;
        auto result2 = PCSystemCmdWait(findstr.c_str());
        if (!result2)
        {
            return result.SetFail("PCSystemCmdWait fail:%s",result2.ErrDesc());
        }
        if (result2.Get().empty())
        {
            return result.SetFail("not find process:%s", szProcessName);
        }
        return result.SetSucc(atoi(result2.Get().c_str()));
#endif        
    }

    /**
    *@brief      通过pid杀死进程，等价于linux的kill函数
    *@param      pid       [in]    进程pid，0代表自己.
    *@param      signum    [in]    信号，SIGKILL(强制杀死且不能被捕获)
    *                                   SIGTERM(友好退出可能被用户捕获)
    *                                   SIGINT(关联ctrl+c，信号被进程树接收到，只能结束前台进程)
    *                                   0(空信号，用来检测进程是否存在，不是原子操作，不一定可靠)
    *@return    成功：CPCResult.Succ  失败：CPCResult.ErrDesc[错误描述]
    */
    static CPCResult<> PCKillProcessPid(int pid, int signum = SIGKILL)
    {
        CPCResult<> result;
#if defined(PCOS_WIN)
        HANDLE process_handle = NULL;
        if (pid == 0) {
            process_handle = ::GetCurrentProcess();
        }
        else {
            process_handle = ::OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION, FALSE, pid);
        }
        if (process_handle == NULL)
        {
            return result.SetSystemFail();
        }
        CPCAutoObj autoClose([&process_handle](){PCCloseHandle(process_handle); });

        switch (signum)
        {
        case SIGTERM:
        case SIGKILL:
        case SIGINT:
        {
            //无条件杀死进程。杀死进程正常返回1
            if (TerminateProcess(process_handle, 1))
                break;

            //如果在调用TerminateProcess之前该进程已经退出，则TerminateProcess将失败，并显示ERROR_ACCESS_DENIED。
            DWORD status;
            DWORD err = GetLastError();
            if (err == ERROR_ACCESS_DENIED &&
                GetExitCodeProcess(process_handle, &status) &&
                status != STILL_ACTIVE)
            {
                return result.SetFail("not find.");
            }
            return result.SetSystemFail(err);
        }
        case 0:
        {
            //判断进程是否存在
            DWORD status;
            if (!GetExitCodeProcess(process_handle, &status))
                return result.SetSystemFail();
            if (status != STILL_ACTIVE)
                return result.SetFail("not find.");
            break;
        }
        default:
            return result.SetFail("Unsupported signal(%d)", signum);
        }
#else
        if (::kill(pid, signum) != 0)
            return result.SetSystemFail();
#endif
        return result;
    }

    /**
    *@brief     杀死进程
    *@param     szProcessName    [in]    进程名称。所有和这个进程名称相同的进程都会杀死。
    *@return    成功：CPCResult.Succ    失败：CPCResult.ErrDesc[错误描述]
    */
    static CPCResult<> PCKillProcess(const char* szProcessName)
    {
        CPCResult<> result;
        auto result2 = PCGetPidByProcessName(szProcessName);
        if(!result2)
        {
            return result.SetFail("PCGetPidByProcessName fail:%s",result2.ErrDesc());
        }
        return PCKillProcessPid(result2.Get());
    }

    /**
    *@brief     将程序添加到防火墙例外列表中(仅支持WINDOWS平台)
    *@param     szExePath               [in]    程序全路径
    *@param     szExeFriendlyAppName    [in]    防火墙中的程序名称
    *@return    是否成功
    */
    static CPCResult<> AddApplicationToExceptionList(const char * szExePath, const char * szExeFriendlyAppName)
    {
        CPCResult<> result;
#if defined(PCOS_WIN)
        if (szExePath == NULL || szExeFriendlyAppName == NULL)
        {
            return result.SetFail("params invalid.");
        }
        WCHAR wstrPath[MAX_PATH] = { 0 };
        WCHAR wstrName[MAX_PATH] = { 0 };
        MultiByteToWideChar(CP_ACP, 0, szExePath, MAX_PATH, wstrPath, MAX_PATH);
        MultiByteToWideChar(CP_ACP, 0, szExeFriendlyAppName, MAX_PATH, wstrName, MAX_PATH);
        BSTR bstrGameExeFullPath = SysAllocString(wstrPath);
        BSTR bstrFriendlyAppName = SysAllocString(wstrName);
        if (bstrGameExeFullPath == NULL || bstrFriendlyAppName == NULL)
        {
            return result.SetSystemFail();
        }

        HRESULT hr = E_FAIL;
        bool bCleanupCOM = false;
        INetFwAuthorizedApplication* pFwApp = NULL;
        INetFwAuthorizedApplications* pFwApps = NULL;

        hr = CoInitialize(0);
        bCleanupCOM = SUCCEEDED(hr);

        //GetFirewallProfile
        INetFwMgr* pFwMgr = NULL;
        INetFwPolicy* pFwPolicy = NULL;
        INetFwProfile* pFwProfile = NULL;

        // Create an instance of the Firewall settings manager 
        hr = CoCreateInstance(__uuidof(NetFwMgr), NULL, CLSCTX_INPROC_SERVER,
            __uuidof(INetFwMgr), (void**)&pFwMgr);
        if (SUCCEEDED(hr))
        {
            hr = pFwMgr->get_LocalPolicy(&pFwPolicy);
            if (SUCCEEDED(hr))
            {
                pFwPolicy->get_CurrentProfile(&pFwProfile);
            }
        }

        // Cleanup 
        if (pFwPolicy) pFwPolicy->Release();
        if (pFwMgr) pFwMgr->Release();
        if (pFwProfile == NULL)
        {
            hr = E_FAIL;
            goto LCleanup;
        }

        hr = pFwProfile->get_AuthorizedApplications(&pFwApps);
        if (FAILED(hr))
            goto LCleanup;

        // Create an instance of an authorized application. 
        hr = CoCreateInstance(__uuidof(NetFwAuthorizedApplication), NULL,
            CLSCTX_INPROC_SERVER, __uuidof(INetFwAuthorizedApplication), (void**)&pFwApp);
        if (FAILED(hr))
            goto LCleanup;

        // Set the process image file name. 
        hr = pFwApp->put_ProcessImageFileName(bstrGameExeFullPath);
        if (FAILED(hr))
            goto LCleanup;

        // Set the application friendly name. 
        hr = pFwApp->put_Name(bstrFriendlyAppName);
        if (FAILED(hr))
            goto LCleanup;

        // Add the application to the collection. 
        hr = pFwApps->Add(pFwApp);

    LCleanup:
        if (bstrFriendlyAppName) SysFreeString(bstrFriendlyAppName);
        if (bstrGameExeFullPath) SysFreeString(bstrGameExeFullPath);
        if (pFwApp) pFwApp->Release();
        if (pFwApps) pFwApps->Release();
        if (pFwProfile) pFwProfile->Release();
        if (bCleanupCOM) CoUninitialize();

        if (SUCCEEDED(hr))
        {
            return result;
        }
        else
        {
            return result.SetSystemFail();
        }
#else
        return result.SetFail("NOT supportted.");
#endif
    }

    /**
    *@brief     取父进程pid
    *@return    父进程pid
    */
    static int GetPPID()
    {
#if defined(PCOS_WIN)
        int parent_pid = -1;
        PROCESSENTRY32 pe;
        pe.dwSize = sizeof(PROCESSENTRY32);
        HANDLE handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
        if (Process32First(handle, &pe))
        {
            do
            {
                if (pe.th32ProcessID == GetCurrentProcessId())
                {
                    parent_pid = pe.th32ParentProcessID;
                    break;
                }
            } while (Process32Next(handle, &pe));
        }
        PCCloseHandle(handle);
        return parent_pid;
#else
        return ::getppid();
#endif
    }

public:
    /**
    *@brief     取cpuid
    *@return    cpuid
    */
    /*static std::string GetCpuSerialNo()
    {
        unsigned int CPUInfo[4] = {0};
        unsigned int InfoType = 0;
#if defined(PCOS_ANDROID)
        return "";
#elif defined(__GNUC__)    
        __cpuid(InfoType, CPUInfo[0],CPUInfo[1],CPUInfo[2],CPUInfo[3]);
#elif defined(_MSC_VER)   
    #if _MSC_VER>=1400    // VC2005才支持__cpuid
        __cpuid((int*)(void*)CPUInfo, (int)InfoType);
    #else
        int ECXValue = 0;
        _asm{
            // load. 读取参数到寄存器.
            mov edi, CPUInfo;    // 准备用edi寻址CPUInfo
            mov eax, InfoType;
            mov ecx, ECXValue;
            // CPUID
            cpuid;
            // save. 将寄存器保存到CPUInfo
            mov    [edi], eax;
            mov    [edi+4], ebx;
            mov    [edi+8], ecx;
            mov    [edi+12], edx;
        }
    #endif
#endif 

        char pszCpuId[MAX_PATH] = {0};
	    snprintf(pszCpuId, sizeof(pszCpuId)-1, "%.8X%.8X%.8X%.8X", CPUInfo[0],CPUInfo[1],CPUInfo[2],CPUInfo[3]);
        return pszCpuId;
    }*/


#if defined(PCOS_WIN)
#else
    /**
    *@brief     Tick2MescAndNext
    *@return    ms
    */
    static uint64_t Tick2MescAndNext(char*& stick)
    {
        static int clktck = sysconf(_SC_CLK_TCK);
        if (!stick || stick[0] == 0)
            return 0;

        uint64_t s = strtoull(stick, &stick, 10);
        return   ((uint64_t)(s)* ((uint64_t)1000L / (double)clktck));
    }
#endif

    

};




#endif    //___PCLIB_S_SYSTUTIL___
